package com.xavier.dong.netty.codec;

import com.xavier.dong.grpc.pojo.StudentPOJO;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;

/**
 * @author XavierDong
 **/
public class NettyServer {
    public static void main(String[] args) throws InterruptedException {

        // 创建 Boss Group 和 Worker Group
        // 说明
        // 1. 创建2个线程组 分别为 bossGroup 和 workerGroup
        // 2. bossGroup 只是处理连接请求，真正和客户端业务处理 会交给 workerGroup 完成
        // 3. 两个 都是 无限 循环
        // 4. bossGroup 和 workerGroup 含有 子线程(NioEventLoop)的 个数
        //     默认是 CPU 的 核数 *2
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();


        try {
            // 创建 服务器端的启动对象，配置启动参数
            ServerBootstrap bootstrap = new ServerBootstrap();

            // 使用 链式编程来进行设置
            bootstrap.group(bossGroup, workerGroup) // 设置 2个 线程组
                    .channel(NioServerSocketChannel.class) // 设置 使用 NioServerSocketChannel 作为服务器的 通道的实现
                    .option(ChannelOption.SO_BACKLOG, 128)  // 设置 线程队列 等待连接的个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 设置 保持 活动连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 创建 一个通道测试对象（匿名对象）

                        // 给 pipeline 设置 处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 可以 用 集合 管理 SocketChannel ，再推送消息时，可以将业务加入 各个 channel 对应的 NIOEventLoop 的taskQueue 或者 ScheduleTaskQueue
                            System.out.println("客户 SockChannel hashcode= " + socketChannel.hashCode());

                            //在 pipeline 中 加入 解码器
                            // 指定 对 哪种对象 进行解码
                            socketChannel.pipeline().addLast("decoder",new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));
                            socketChannel.pipeline().addLast(new NettyServerHandler());

                        }
                    }); // 给 我们的 WorkerGroup 的 某一个 EventLoop 对应的管道 设置处理器


            System.out.println("....服务器 is  Ready...");

            // 绑定一个端口，并且 同步 ,生成了 一个 ChannelFuture 对象
            // 启动 服务器 并 绑定端口
            ChannelFuture channelFuture = bootstrap.bind(6668).sync();

            // 注册 监听器 ， 监控 我们 关心的事件
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess())
                        System.out.println("监听端口 6668 成功");
                    else
                        System.out.println("监听端口 6668 失败");
                }
            });


            // 对关闭通道 进行 监听
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}
